package com.bitcoin.scheduler.task;

import com.bitcoin.scheduler.service.BccPriceInfoService;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.ListUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigInteger;
import java.text.ParseException;
import java.util.*;
import java.util.Calendar;

/**
 * 币基本信息爬虫数据清洗任务
 */
@Service
@Slf4j
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class BccPriceDetailFillingTask implements Job {

    @Autowired
    private BccPriceInfoService priceInfoService;

    @Override
    @SuppressWarnings("unchecked")
    public void execute(JobExecutionContext context) throws JobExecutionException {
        Set<BigInteger> ignoreDateSets = (Set<BigInteger>) context.getJobDetail().getJobDataMap().getOrDefault("ignoreDateSets", Sets.newIdentityHashSet());
        log.info("补全价格数据任务开始 忽略时间点数量 {}", ignoreDateSets.size());
        //取上N个星期待补充时间点
        //如果待补充时间点为空 取N+1 到N的的时间点
        //如果待补充时间点为2018年4月份之前退出
        //调用币价格任务补充时间点数据
        int pointCount = 0;
        long startTime = System.currentTimeMillis();
        int days = 2;
        Date beginDate = DateUtils.addDays(new Date(), -days);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(beginDate);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        //整分
        beginDate = calendar.getTime();

        Date startDate = beginDate;
        Date previousEndDate = DateUtils.addDays(new Date(), -1);
        calendar.setTime(previousEndDate);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        //整分
        previousEndDate = calendar.getTime();

        Date finalDate;
        try {
            finalDate = DateUtils.parseDate("2018/04/01", "yyyy/MM/dd");
        } catch (ParseException e) {
            finalDate = DateUtils.addMonths(new Date(), -6);
        }
        //每补60个时间点完成一次任务
        while (beginDate.after(finalDate) && pointCount <= 60) {
            List<BigInteger> allPointDateList = getAllDatePointList(beginDate, previousEndDate);
            List<BigInteger> existsPointDateList = priceInfoService.getPriceInfoDetailDao().existsDatePointList(beginDate, previousEndDate);

            List<BigInteger> notExistsDatePoint = ListUtils.subtract(allPointDateList, existsPointDateList);
            if (CollectionUtils.isNotEmpty(notExistsDatePoint)) {

                log.info("补全价格数据任务 时间范围{}->{} 共有时间点{}个 已有{}个 待补充{}个",
                    DateFormatUtils.format(beginDate, DateFormatUtils.ISO_8601_EXTENDED_DATETIME_FORMAT.getPattern()),
                    DateFormatUtils.format(previousEndDate, DateFormatUtils.ISO_8601_EXTENDED_DATETIME_FORMAT.getPattern()),
                    allPointDateList.size(), existsPointDateList.size(), notExistsDatePoint.size());
                //从大到小排序
                notExistsDatePoint.sort(Comparator.reverseOrder());
                for (BigInteger datePoint : notExistsDatePoint) {
                    if (ignoreDateSets.contains(datePoint)) {
                        continue;
                    }
                    pointCount++;
                    try {
                        priceInfoService.syncPriceDetail(new Date(datePoint.longValue() * 1000));
                    } catch (Exception e) {
                        ignoreDateSets.add(datePoint);
                    }
                    if (pointCount >= 60) {
                        break;
                    }
                }
            }
            days++;
            previousEndDate = beginDate;
            beginDate = DateUtils.addDays(new Date(), -days);
        }
        log.info(
            "补全价格数据任务一个周期完成 {}->{} 共补充[{}]个时间点数据 耗时{}s",
            DateFormatUtils.format(startDate, DateFormatUtils.ISO_8601_EXTENDED_DATETIME_FORMAT.getPattern()),
            DateFormatUtils.format(previousEndDate, DateFormatUtils.ISO_8601_EXTENDED_DATETIME_FORMAT.getPattern()),
            pointCount,
            (System.currentTimeMillis() - startTime) / 1000.0
        );
        context.getJobDetail().getJobDataMap().put("ignoreDateSets", ignoreDateSets);
    }

    //取得时间范围内所有分钟时间点
    public List<BigInteger> getAllDatePointList(Date beginDate, Date endDate) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(beginDate);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        beginDate = calendar.getTime();
        calendar.setTime(endDate);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        endDate = calendar.getTime();
        List<BigInteger> allDatePointList = Lists.newArrayList();
        while (beginDate.before(endDate)) {
            beginDate = DateUtils.addMinutes(beginDate, 1);
            BigInteger date = BigInteger.valueOf(beginDate.getTime() / 1000);
            if (!allDatePointList.contains(date)) {
                allDatePointList.add(date);
            }
        }
        if (!allDatePointList.contains(BigInteger.valueOf(endDate.getTime() / 1000))) {
            allDatePointList.add(BigInteger.valueOf(beginDate.getTime() / 1000));
        }
        return allDatePointList;
    }
}
